package top.linyuxb.lycloud.config.starter.common;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import top.linyuxb.lycloud.common.properties.LyConfigProperties;
import top.linyuxb.lycloud.config.starter.annotation.LyConfigListener;
import top.linyuxb.lycloud.config.starter.annotation.LyConfigurationProperties;
import top.linyuxb.lycloud.config.starter.annotation.LyConfigurationValue;
import top.linyuxb.lycloud.config.starter.dto.LyConfigListenerDto;
import top.linyuxb.lycloud.config.starter.dto.LyConfigServerDto;
import top.linyuxb.lycloud.config.starter.utils.StringToTypeConverterUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * Created by Intellij IDEA.
 *
 * @Author: linyuxb
 * @Date: 2024/6/13 16:29
 * @Desc: ly-config bean后置处理器
 */
@Slf4j
public class LyConfigBeanPostProcessor implements BeanPostProcessor {
    private LyConfigProperties lyRpcClientProperties;

    public LyConfigBeanPostProcessor(LyConfigProperties lyRpcClientProperties) {
        this.lyRpcClientProperties = lyRpcClientProperties;
    }

    public LyConfigBeanPostProcessor() {
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> objClz;
        if (AopUtils.isAopProxy(bean)) {
            objClz = AopUtils.getTargetClass(bean);
        } else {
            objClz = bean.getClass();
        }
        try {
            LyConfigurationProperties lyConfigurationProperties = objClz.getAnnotation(LyConfigurationProperties.class);
            // 1、处理类参数
            if (Objects.nonNull(lyConfigurationProperties)) {
                this.handleClassField(bean, lyConfigurationProperties, objClz);
            }
            // 2、处理属性参数
            else {
                this.handleFieldField(bean, objClz);
            }
            // 3、处理监听事件
            this.handleListener(bean, objClz);
        } catch (Exception e) {
            log.error("LyConfigBeanPostProcessor postProcessAfterInitialization error", e);
            throw new BeanCreationException(beanName, e);
        }
        return bean;
    }

    /**
     * 处理参数类
     *
     * @param bean
     * @param lyConfigurationProperties
     * @param objClz
     */
    private void handleClassField(Object bean, LyConfigurationProperties lyConfigurationProperties, Class<?> objClz) {
        String prefix = lyConfigurationProperties.prefix();
        boolean havePrefix = StrUtil.isNotBlank(prefix);
        for (Field field : objClz.getDeclaredFields()) {
            String key = field.getName();
            if (havePrefix) {
                key = prefix + "." + key;
            }
            LyConfigServerDto lyConfigServerDto = LyConfigServerDto.builder()
                    .env(lyRpcClientProperties.getEnv())
                    .app(lyRpcClientProperties.getApp())
                    .key(key)
                    .bean(bean)
                    .field(field)
                    .defaultValue(null)
                    .build();
            LyConfigService.saveServer(key, lyConfigServerDto);
            LyConfigService.setValue(lyRpcClientProperties.getRegisterType(), lyConfigServerDto);
        }
    }

    /**
     * 处理属性参数
     *
     * @param bean
     * @param objClz
     */
    private void handleFieldField(Object bean, Class<?> objClz) {
        for (Field field : objClz.getDeclaredFields()) {
            LyConfigurationValue lyConfigurationValue = field.getAnnotation(LyConfigurationValue.class);
            if (Objects.nonNull(lyConfigurationValue)) {
                String key = lyConfigurationValue.value();
                if (key.startsWith("${")) {
                    key = key.substring(2);
                }
                if (key.endsWith("}")) {
                    key = key.substring(0, key.length() - 1);
                }
                Object defaultVal = null;
                if (key.contains(":")) {
                    List<String> split = StrUtil.split(key, ":");
                    key = split.get(0);
                    defaultVal = StringToTypeConverterUtil.convertStringToType(field.getType(), split.get(1));
                }
                LyConfigServerDto lyConfigServerDto = LyConfigServerDto.builder()
                        .env(lyRpcClientProperties.getEnv())
                        .app(lyRpcClientProperties.getApp())
                        .key(key)
                        .bean(bean)
                        .field(field)
                        .defaultValue(defaultVal)
                        .build();
                LyConfigService.saveServer(key, lyConfigServerDto);
                LyConfigService.setValue(lyRpcClientProperties.getRegisterType(), lyConfigServerDto);
            }
        }
    }

    /**
     * 处理监听
     *
     * @param bean
     * @param objClz
     */
    private void handleListener(Object bean, Class<?> objClz) {
        for (Method method : objClz.getDeclaredMethods()) {
            LyConfigListener lyConfigListener = method.getAnnotation(LyConfigListener.class);
            if (Objects.nonNull(lyConfigListener)) {
                String[] keys = lyConfigListener.keys();
                ChangeTypeEnum changeTypeEnum = lyConfigListener.changeType();
                LyConfigService.saveListener(
                        LyConfigListenerDto.builder()
                                .env(lyRpcClientProperties.getEnv())
                                .app(lyRpcClientProperties.getApp())
                                .keys(keys)
                                .changeTypeEnum(changeTypeEnum)
                                .bean(bean)
                                .method(method)
                                .build()
                );
            }
        }
    }

}
